package com.zues.daiommiddleware.service;

import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriber;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
import java.util.Objects;

/**
 * 语音识别服务
 *
 * @author: zues
 * @date: 2024/9/6
 * @description: 集成阿里云语音识别
 */
@Service
@NoArgsConstructor
public class SpeechTranscriberService {

    /**
     * 存储应用程序的唯一标识符
     */
    private String appKey;

    /**
     * 存储访问令牌，用于验证请求的合法性
     */
    private String accessToken;

    /**
     * 初始化NlsClient对象，用于后续的语音服务调用
     */
    NlsClient client;

    /**
     * 设备音频输入源，用于从麦克风获取音频数据
     */
    TargetDataLine targetDataLine;

    /**
     * 构造函数，用于初始化SpeechTranscriberService实例
     *
     * @param appKey 应用的唯一标识符，用于识别不同的应用
     * @param token  访问服务的令牌，用于验证访问者的身份
     */
    public SpeechTranscriberService(String appKey, String token) {
        this.appKey = appKey;
        this.accessToken = token;
        // 创建NlsClient实例,应用全局创建一个即可,默认服务地址为阿里云线上服务地址
        client = new NlsClient(accessToken);
    }

    /**
     * 构造函数，用于初始化SpeechTranscriberService对象
     *
     * @param appKey 应用的唯一标识符，用于识别不同应用
     * @param token  访问服务的令牌，用于认证用户身份
     * @param url    服务的访问地址，用于指定与服务端通信的URL
     */
    public SpeechTranscriberService(String appKey, String token, String url) {
        this.appKey = appKey;
        this.accessToken = token;
        // 创建NlsClient实例,应用全局创建一个即可,用户指定服务地址
        client = new NlsClient(url, accessToken);
    }

    public void process(SpeechTranscriberListener listener) {
        SpeechTranscriber transcriber = null;
        try {
            // 创建实例,建立连接
            transcriber = new SpeechTranscriber(client, listener);
            transcriber.setAppKey(appKey);
            // 输入音频编码方式
            transcriber.setFormat(InputFormatEnum.PCM);
            // 输入音频采样率
            transcriber.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
            // 是否返回中间识别结果
            transcriber.setEnableIntermediateResult(true);
            // 是否生成并返回标点符号
            transcriber.setEnablePunctuation(true);
            // 是否将返回结果规整化,比如将一百返回为100
            transcriber.setEnableITN(false);

            //此方法将以上参数设置序列化为json发送给服务端,并等待服务端确认
            transcriber.start();
            /*
                创建一个AudioFormat实例，指定音频的编码格式
                该实例定义了音频的采样率（16000样本每秒）、每个样本的位深度（16位）、
                声道数量（单声道）、是否大端序编码（小端序）以及是否压缩编码（未压缩
             */
            AudioFormat audioFormat = new AudioFormat(16000.0F, 16, 1, true, false);
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
            targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
            //如何查看当前线程是否有锁
            targetDataLine.open(audioFormat);
            targetDataLine.start();
            System.out.println("You can speak now!");
            int nByte = 0;
            final int bufSize = 3200;
            byte[] buffer = new byte[bufSize];
            while ((nByte = targetDataLine.read(buffer, 0, bufSize)) > 0) {
                // 直接发送麦克风数据流
                transcriber.send(buffer, nByte);
            }

            transcriber.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != transcriber) {
                transcriber.close();
            }
        }
    }

    public void shutdown(SpeechTranscriberService speechTranscriberService) {
        //先关闭设备，否则占用进程无法开启下一次识别
        if(!Objects.isNull(targetDataLine)){
            targetDataLine.close();
            client.shutdown();
        }
        //手动释放对象
        speechTranscriberService = null;
    }
}
